package com.autumn.zero.authorization.application.services.impl;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.autumn.mybatis.criterion.EntityQuery;
import com.autumn.security.constants.UserStatusConstants;
import com.autumn.util.AutoMapUtils;
import com.autumn.util.DataRollbackException;
import com.autumn.util.ExceptionUtils;
import com.autumn.zero.application.services.AbstractZeroQueryAppService;
import com.autumn.zero.authorization.application.dto.PermissionDto;
import com.autumn.zero.authorization.application.dto.PermissionGrantedInput;
import com.autumn.zero.authorization.application.dto.PermissionResourcesModuleDto;
import com.autumn.zero.authorization.application.dto.modules.ResourcesTypeInput;
import com.autumn.zero.authorization.application.dto.users.ResetPasswordInput;
import com.autumn.zero.authorization.application.dto.users.UserDetailsOutput;
import com.autumn.zero.authorization.application.dto.users.UserInput;
import com.autumn.zero.authorization.application.dto.users.UserOutput;
import com.autumn.zero.authorization.application.dto.users.UserPermissionOutput;
import com.autumn.zero.authorization.application.dto.users.UserRoleOutput;
import com.autumn.zero.authorization.application.services.IUserAppService;
import com.autumn.zero.authorization.entitys.users.User;
import com.autumn.zero.authorization.entitys.users.UserPermission;
import com.autumn.zero.authorization.entitys.users.querys.UserRoleQuery;
import com.autumn.zero.authorization.repositorys.users.IUserRepository;
import com.autumn.zero.authorization.repositorys.users.querys.IUserRoleQueryRepository;
import com.autumn.zero.authorization.services.IAuthorizationService;
import com.autumn.zero.authorization.services.IResourcesService;
import com.autumn.zero.authorization.values.ResourcesModulePermissionTreeValue;
import com.autumn.zero.authorization.values.ResourcesModuleTreeValue;

/**
 * 用户应用服务
 * 
 * @author 杨昌国 2018-12-10 15:58:04
 */
public class UserAppServiceImpl extends AbstractZeroQueryAppService<Long, User, IUserRepository, UserOutput>
		implements IUserAppService {

	@Autowired
	private IUserRepository repository;

	@Autowired
	private IUserRoleQueryRepository userRoleQueryRepository;

	@Autowired
	private IAuthorizationService authorizationService;

	@Autowired
	private IResourcesService resourcesService;

	@Override
	public String getModuleName() {
		return "用户管理";
	}

	@Override
	protected IUserRepository getQueryRepository() {
		return this.repository;
	}

	/**
	 * 
	 */
	@Override
	protected void queryByOrder(EntityQuery<User> query) {
		query.orderBy(User.FILED_ID);
	}

	private Set<String> searchMembers = new HashSet<>();

	@Override
	protected Set<String> getSearchMembers() {
		if (searchMembers.size() == 0) {
			searchMembers.add(User.FILED_USER_NAME);
			searchMembers.add(User.FILED_REAL_NAME);
			searchMembers.add(User.FILED_PHONE_NUMBER);
			searchMembers.add(User.FILED_EMAIL_ADDRESS);
		}
		return searchMembers;
	}

	private List<UserRoleOutput> queryRoles(long userId) {
		EntityQuery<UserRoleQuery> query = new EntityQuery<>(UserRoleQuery.class);
		query.eq(UserRoleQuery.FILED_USER_ID, userId).orderBy(UserRoleQuery.FILED_ID);
		List<UserRoleQuery> roles = query.selectByList(this.userRoleQueryRepository);
		return AutoMapUtils.mapList(roles, UserRoleOutput.class);
	}

	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public UserDetailsOutput add(UserInput input) {
		ExceptionUtils.checkNotNull(input, "input");
		input.valid();
		User entity = AutoMapUtils.map(input, User.class);
		entity.setPassword("123456");
		entity.setStatus(UserStatusConstants.NORMAL);
		authorizationService.addUser(entity, true);
		UserDetailsOutput result = AutoMapUtils.map(entity, UserDetailsOutput.class);
		result.setRoles(this.queryRoles(entity.getId()));
		return result;
	}

	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public UserDetailsOutput update(UserInput input) {
		ExceptionUtils.checkNotNull(input, "input");
		input.valid();
		User entity = AutoMapUtils.map(input, User.class);
		entity.setStatus(UserStatusConstants.NORMAL);
		authorizationService.updateUser(entity);
		UserDetailsOutput result = AutoMapUtils.map(entity, UserDetailsOutput.class);
		result.setRoles(this.queryRoles(entity.getId()));
		return result;
	}
	
	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public void resetPassword(ResetPasswordInput input) {
		ExceptionUtils.checkNotNull(input, "input");
		input.valid();
		authorizationService.resetPassword(input.getId(), input.getNewPassword());
	}

	@Override
	public UserDetailsOutput queryById(Long id) {
		User entity = repository.get(id);
		UserDetailsOutput result = null;
		if (entity != null) {
			result = AutoMapUtils.map(entity, UserDetailsOutput.class);
			result.setRoles(this.queryRoles(entity.getId()));
		}
		return result;
	}

	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public void deleteById(Long id) {
		authorizationService.deleteUserById(id);
	}

	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public UserPermissionOutput authorize(PermissionGrantedInput input) {
		ExceptionUtils.checkNotNull(input, "input");
		input.valid();
		List<UserPermission> permissions = AutoMapUtils.mapList(input.getPermissions(), UserPermission.class,
				(s, t) -> {
					t.setName(s.getPermissionName());
				});
		User user = authorizationService.authorizeByUser(input.getId(), input.getResourcesType(), permissions);
		UserPermissionOutput result = AutoMapUtils.map(user, UserPermissionOutput.class);
		result.setPermissions(AutoMapUtils.mapList(permissions, PermissionResourcesModuleDto.class, (s, t) -> {
			t.setPermissionName(s.getName());
		}));
		return result;
	}

	@Override
	public UserPermissionOutput authorizeByQuery(PermissionDto input) {
		ExceptionUtils.checkNotNull(input, "input");
		input.valid();
		User user = authorizationService.getUser(input.getId(), false);
		if (user == null) {
			return null;
		}
		UserPermissionOutput result = AutoMapUtils.map(user, UserPermissionOutput.class);
		List<UserPermission> permissions = authorizationService.queryUserPermissions(input.getId());
		result.setPermissions(AutoMapUtils.mapList(permissions, PermissionResourcesModuleDto.class, (s, t) -> {
			t.setPermissionName(s.getName());
		}));
		return result;
	}

	@Override
	public List<ResourcesModulePermissionTreeValue> authorizeByModulePermissionTree(PermissionDto input) {
		List<UserPermission> permissions = authorizationService.queryUserPermissions(input.getId());
		return resourcesService.matchByPermissionTree(input.getResourcesType(), permissions);
	}

	@Override
	public List<ResourcesModuleTreeValue> queryUserByMenuTree(ResourcesTypeInput input) {
		return authorizationService.queryUserByMenuTree(input.getResourcesType(), this.getSession().getUserId());
	}

	@Override
	@Transactional(rollbackFor = DataRollbackException.class)
	public void authorizeByAllPermission(PermissionDto input) {
		ExceptionUtils.checkNotNull(input, "input");
		input.valid();
		authorizationService.authorizeByUserAllPermission(input.getId(), input.getResourcesType());
	}	
}
